﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Forums.ForumsClient.Models;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
using Web = Microsoft.Forums.MicrosoftForumsProvider.Forums;
using System.Globalization;


namespace Microsoft.Forums.ForumsClient.Views
{
    /// <summary>
    /// Interaction logic for ThreadedView.xaml
    /// </summary>
    public partial class ThreadedView : UserControl, IFilterableView
    {
        Dictionary<string, string> columnHeaderPropertyMap = new Dictionary<string, string>();

        GridViewColumnHeader lastHeaderClicked;
        ListSortDirection lastDirection = ListSortDirection.Ascending;

        /// <summary>
        /// Gets the post model container.
        /// </summary>
        /// <value>The post model container.</value>
        private IPostModelContainer<ThreadedPostViewModel> PostModelContainer
        {
            get
            {
                return (IPostModelContainer<ThreadedPostViewModel>)this.DataContext;
            }
        }

        public ThreadedView()
        {
            InitializeComponent();
            columnHeaderPropertyMap["Subject"] = "Post.Subject";
            columnHeaderPropertyMap["Author"] = "Post.CreatedBy.DisplayName";
            columnHeaderPropertyMap["Created Date"] = "Post.CreatedOn";
            columnHeaderPropertyMap["Modified Date"] = "Post.ThreadModifiedOn";

           
        }


        #region IFilterableView Members


        /// <summary>
        /// Gets the filter settings.
        /// </summary>
        /// <value>The filter settings.</value>
        public ThreadFilterSettings FilterSettings
        {
            get 
            {
                IFilterableModel settings = this.DataContext as IFilterableModel;
                if (settings != null)
                {
                    return settings.FilterSettings;
                }
                else
                {
                    return null;
                }
            }
        }


       /// <summary>
       /// Filter function that filters the collection view source based on user filter settings
       /// </summary>
        public void Filter()
        {
            ICollectionView sourceCollection = (ICollectionView)threadedView.ItemsSource;
            if (sourceCollection != null)
            {
                sourceCollection.Filter = ShouldInclude;
            }
        }

        /// <summary>
        /// Determines whether the specified item is included in the view.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <returns>
        /// 	<c>true</c> if the specified item is filtered; otherwise, <c>false</c>.
        /// </returns>
        private bool ShouldInclude(object item)
        {
            ThreadedPostViewModel postModel = item as ThreadedPostViewModel;
            ThreadFilterSettings filters = FilterSettings;

            if (postModel != null && filters != null && postModel.ThreadIfRootPost != null)
            {
                bool result = true;
                if (filters.IsCheckedHelpful)
                {
                    result &= (bool)postModel.ThreadIfRootPost.IsHelpful;
                }
                if (filters.IsCheckedNoReplies)
                {
                    result &= postModel.ThreadIfRootPost.TotalReplies <= 0;
                }
                if (filters.IsCheckedProposedAnswers)
                {
                    result &= (bool)postModel.ThreadIfRootPost.HasProposedAnswers;
                }
                if (filters.IsCheckedAnswered)
                {
                    result &= (bool)postModel.ThreadIfRootPost.IsAnswered;
                }
                if (filters.IsCheckedUnanswered)
                {
                    result &= ((bool)!postModel.ThreadIfRootPost.IsAnswered && 
                               (Web.ThreadType)postModel.ThreadIfRootPost.ThreadType != Web.ThreadType.Comment);
                }
                if (filters.IsCheckedGeneralDiscussion)
                {
                    result &= (bool)((Web.ThreadType)postModel.ThreadIfRootPost.ThreadType == Web.ThreadType.Comment);
                }
                if (!String.IsNullOrEmpty(filters.SearchText))
                {
                    string searchText = filters.SearchText.ToUpper(CultureInfo.InvariantCulture);
                    result &= postModel.Post.Subject.ToUpper(CultureInfo.InvariantCulture).Contains(searchText);
                }

                return result;
            }
            else
            {
                return false;
            }
        }

        #endregion
        /// <summary>
        /// Called when the selected post is changed. Updated the datamodel.
        /// </summary>
        /// <param name="sender">The object that raised this event</param>
        /// <param name="e">The event arguments</param>
        private void ColumnsTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (PostModelContainer != null)
            {
                PostModelContainer.SelectedPostModel = threadedView.SelectedItem as ThreadedPostViewModel;
                MarkAsRead_Executed(null, null);
            }
        }

        /// <summary>
        /// Manually handle the right arrow click to expand the selected treeviewitem
        /// 
        /// For some reason in this customized treeview to enable columns the default right arrow behavior
        /// doesn't work
        /// Oddly enough, the left arrow key works fine.  
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ThreadedView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Right)
            {
                ColumnsTreeViewItem treeViewItem = e.OriginalSource as ColumnsTreeViewItem;
                if (treeViewItem != null)
                {
                    treeViewItem.IsExpanded = true;
                }
            }
        }

        #region Sorting
        /// <summary>
        /// Handles the Click event of the ColumnHeader control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ColumnHeader_Click(object sender, RoutedEventArgs e)
        {

         GridViewColumnHeader headerClicked =
                  e.OriginalSource as GridViewColumnHeader;
            ListSortDirection direction;

            if (headerClicked != null)
            {
                if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
                {
                    if (headerClicked != lastHeaderClicked)
                    {
                        direction = ListSortDirection.Ascending;
                    }
                    else
                    {
                        if (lastDirection == ListSortDirection.Ascending)
                        {
                            direction = ListSortDirection.Descending;
                        }
                        else
                        {
                            direction = ListSortDirection.Ascending;
                        }
                    }

                    
                    string header = headerClicked.Column.Header as string;
                    Sort(header, direction);

                    if (direction == ListSortDirection.Ascending)
                    {
                        headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate;
                    }
                    else
                    {
                        headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate;
                    }

                    // Remove arrow from previously sorted header
                    if (lastHeaderClicked != null && lastHeaderClicked != headerClicked)
                    {
                        lastHeaderClicked.Column.HeaderTemplate = null;
                    }


                    lastHeaderClicked = headerClicked;
                    lastDirection = direction;
                }
            }
        }


        /// <summary>
        /// Sorts the specified sort by.
        /// </summary>
        /// <param name="sortBy">The sort by.</param>
        /// <param name="direction">The direction.</param>
        private void Sort(string sortBy, ListSortDirection direction)
        {
            if (!columnHeaderPropertyMap.ContainsKey(sortBy)) 
                throw new ArgumentException("sortBy is not in the columnHeader map");

            PostViewModel previousSelectedItem = this.threadedView.SelectedItem as PostViewModel;
            if (previousSelectedItem != null)
            {
                sortBy = columnHeaderPropertyMap[sortBy];
                ICollectionView dataView = (ICollectionView)threadedView.ItemsSource;

                using (dataView.DeferRefresh())
                {
                    dataView.SortDescriptions.Clear();
                    SortDescription sd = new SortDescription(sortBy, direction);
                    dataView.SortDescriptions.Add(sd);
                }

                // reselect item after sort
                SelectItemIfLoaded(threadedView, previousSelectedItem);
            }
        }


        /// <summary>
        /// Selects the item in the tree view if it is loaded already in memory.
        /// 
        /// This code is based off of this blog post:
        /// http://blog.quantumbitdesigns.com/2008/07/22/programmatically-selecting-an-item-in-a-treeview/
        /// </summary>
        /// <param name="parentContainer">The parent container.</param>
        /// <param name="itemToFind">The item to find and select.</param>
        private void SelectItemIfLoaded(ItemsControl parentContainer, PostViewModel itemToFind)
        {
            foreach (var item in parentContainer.Items)
            {
                var container = parentContainer.ItemContainerGenerator.ContainerFromItem(item) as ColumnsTreeViewItem;
                if (container != null && item == itemToFind)
                {
                    container.IsSelected = true;
                    container.BringIntoView();
                    container.Focus();
                }
            }

            foreach (var item in parentContainer.Items)
            {
                var container = parentContainer.ItemContainerGenerator.ContainerFromItem(item) as ColumnsTreeViewItem;
                if (container != null && container.Items.Count > 0)
                {
                    if (container.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                    {
                        SelectItemIfLoaded(container, itemToFind);
                    }
                    else
                    {
                        EventHandler statusChanged = null;
                        statusChanged = 
                            delegate
                            {
                                if (container.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                                {
                                    SelectItemIfLoaded(container, itemToFind);
                                    container.ItemContainerGenerator.StatusChanged -= statusChanged;
                                }
                            };
                        container.ItemContainerGenerator.StatusChanged += statusChanged;
                    }
                }
            }
        }
        #endregion

        #region Command Handlers
        #region Show Create Reply Form Command Handlers
        /// <summary>
        /// Handles the CanExecute event of the ShowCreateReplyForm command.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowCreateReplyForm_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = PostModelContainer.SelectedPostModel != null;
        }

        /// <summary>
        /// Handles the Executed event of the ShowCreateReplyForm command.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowCreateReplyForm_Executed(object sender, ExecutedRoutedEventArgs e)
        {
           // show reply form
        }
        #endregion

        #region Mark As Answer Command Handlers
        /// <summary>
        /// Handles the CanExecute event of the MarkAsAnswer command.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void MarkAsAnswer_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = PostModelContainer.SelectedPostModel != null && PostModelContainer.SelectedPostModel.CanMarkAsAnswer;
        }

        /// <summary>
        /// Handles the Executed event of the MarkAsAnswer command.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void MarkAsAnswer_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (PostModelContainer.SelectedPostModel != null)
            {
                PostModelContainer.SelectedPostModel.MarkAsAnswer();
            }
        }
        #endregion

        #region Mark as Read Command Handler
        /// <summary>
        /// Handles the CanExecute event of the MarkAsRead command.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void MarkAsRead_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = PostModelContainer.SelectedPostModel != null && PostModelContainer.SelectedPostModel.CanMarkAsRead;
        }

        /// <summary>
        /// Handles the Executed event of the MarkAsRead command.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void MarkAsRead_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (PostModelContainer.SelectedPostModel != null)
            {
                PostModelContainer.SelectedPostModel.MarkAsRead();
            }
        }
        #endregion
        #endregion
    }
}
